package wechat

import (
	"reflect"
	"strconv"
	"encoding/xml"
	"we-helper/common"
	"github.com/astaxie/beego/logs"
)

type Wechat struct {
	Handlers map[string]MessageHandler
	TmpName string
	LckName string
}

func NewWechat() *Wechat {
	return &Wechat{Handlers: make(map[string]MessageHandler)}
}

func (this *Wechat) AddHandler(key string, handler MessageHandler) {
	this.Handlers[key] = handler
}

func (this *Wechat) Serve(config MpConfig, input []byte, sign, timestamp, nonce string) string {
	requestBody := &EncryptRequestBody{}
	xml.Unmarshal(input, requestBody)
	//将加密后获得的字符串与signature对比，如果一致，说明该请求来源于微信
	if Validate(config, sign, timestamp, nonce) {
		random, rawXMLMsgBytes, _ := DecryptMsg(config, requestBody.Encrypt)
		logs.Debug(string(rawXMLMsgBytes))
		msg := MixMessage{}
		xml.Unmarshal(rawXMLMsgBytes, &msg)
		handler := this.Handlers[msg.GetHandleKey()]
		if handler != nil {
			reply := handler.Handle(msg)
			value := reflect.ValueOf(reply.MsgData)
			//msgData must be a ptr
			kind := value.Kind().String()
			if "ptr" == kind {
				params := make([]reflect.Value, 1)
				params[0] = reflect.ValueOf(msg.FromUserName.Value)
				value.MethodByName("SetToUserName").Call(params)

				params[0] = reflect.ValueOf(msg.ToUserName.Value)
				value.MethodByName("SetFromUserName").Call(params)

				params[0] = reflect.ValueOf(reply.MsgType)
				value.MethodByName("SetMsgType").Call(params)

				params[0] = reflect.ValueOf(common.GetCurrTs())
				value.MethodByName("SetCreateTime").Call(params)
				responseXml, err := xml.Marshal(reply.MsgData)
				if err != nil {
					logs.Error(err)
				}
				encryptedMsg, _ := EncryptMsg(config, random, responseXml)
				////TODO timestamp nonce 则自己生成
				msgSignature := SignatureMsg(config, timestamp, nonce, string(encryptedMsg))
				ts, _ := strconv.ParseInt(timestamp, 10, 64);
				replyMsg := ResponseEncryptedXMLMsg{
					EncryptedMsg: CDATA{Value: string(encryptedMsg)},
					MsgSignature: msgSignature,
					Timestamp:    ts,
					Nonce:        nonce,
				}
				reply, _ := xml.Marshal(replyMsg)
				return string(reply)
			}
		} else {
			logs.Warn("message listener not exists: ", msg)
		}
	}
	return "success"
}
